package cn.wh.ymcc.serivce.impl;

import cn.wh.ymcc.doc.CourseDoc;
import cn.wh.ymcc.domain.*;
import cn.wh.ymcc.dto.CourseDto;
import cn.wh.ymcc.dto.MessageSmsDto;
import cn.wh.ymcc.dto.UserSmsDto;
import cn.wh.ymcc.feignclients.CourseSearchFeignClient;
import cn.wh.ymcc.feignclients.MediaFileFeignClient;
import cn.wh.ymcc.mapper.CourseMapper;
import cn.wh.ymcc.result.JSONResult;
import cn.wh.ymcc.serivce.service.*;
import cn.wh.ymcc.util.AssertUtil;
import cn.wh.ymcc.util.StrUtils;
import cn.wh.ymcc.vo.CourseDetailInfoVo;
import cn.wh.ymcc.vo.CourseItemVo;
import cn.wh.ymcc.vo.CourseOrderVo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static cn.wh.ymcc.constants.MqConstants.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author nidie.wang
 * @since 2022-07-21
 */
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    @Autowired
    private ITeacherService teacherService;
    @Autowired
    private ICourseDetailService courseDetailService;
    @Autowired
    private ICourseResourceService courseResourceService;
    @Autowired
    private ICourseMarketService courseMarketService;
    @Autowired
    private ICourseTeacherService courseTeacherService;
    @Autowired
    private ICourseTypeService courseTypeService;
    @Autowired
    private ICourseSummaryService courseSummaryService;
    @Autowired
    private CourseSearchFeignClient courseSearchFeignClient;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private ICourseChapterService courseChapterService;
    @Autowired
    private MediaFileFeignClient mediaFileFeignClient;

    @Override
    @Transactional
    public void save(CourseDto dto) {
        Course course = dto.getCourse();
        CourseDetail courseDetail = dto.getCourseDetail();
        CourseMarket courseMarket = dto.getCourseMarket();
        CourseResource courseResource = dto.getCourseResource();
        List<Long> teacharIds = dto.getTeacharIds();
        //1.参数校验  JSR303=====================
        //2.课程不能被注册========================
        Course courseTmp = selectByName(course.getName());
        AssertUtil.isNull(courseTmp,"课程已被注册！！！");
        //* 3.保存数据===========================
        //* 保存课程
        // 做必要的参数的初始化  状态、讲师、  谁来添加的课程
        // 有些初始化的值，必须要在service层做填写，防止被黑客黑了
        course.setStatus(Course.STATE_OFFLINE);
        //@TODO 后面做了登录之后来补充
        course.setLoginId(1L);
        course.setLoginUserName("yhptest1");
        List<Teacher> teachers = teacherService.selectBatchIds(teacharIds);
        // 整成stream
        StringBuilder sb = new StringBuilder();
        teachers.forEach(teacher -> {
            sb.append(teacher.getName()).append(",");
        });
        course.setTeacherNames(sb.toString());
        insert(course);
        //* 保存课程详情===========================
        courseDetail.setId(course.getId());
        courseDetailService.insert(courseDetail);

        //* 保存课程销售===========================
        courseMarket.setId(course.getId());
        courseMarketService.insert(courseMarket);

        //* 保存课程讲师===========================
        teacharIds.forEach(id->{
            CourseTeacher courseTeacher = new CourseTeacher();
            courseTeacher.setCourseId(course.getId());
            courseTeacher.setTeacherId(id);
            courseTeacherService.insert(courseTeacher);
        });
        //* 保存课程资源===========================
        courseResource.setCourseId(course.getId());
        courseResourceService.insert(courseResource);

        //* 初始化课程统计===========================
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(course.getId());
        courseSummaryService.insert(courseSummary);

        //课程类型表中的课程数+1======================
        CourseType type = courseTypeService.selectById(course.getCourseTypeId());
        type.setTotalCount(type.getTotalCount() + 1);
        courseTypeService.updateById(type);
    }

    private Course selectByName(String name) {
        Wrapper<Course> tWrapper = new EntityWrapper<Course>();
        tWrapper.eq("name",name);
        return selectOne(tWrapper);
    }

    /**
     * 课程上架
     * @param courseId
     */
    @Override
    @Transactional
    public void onLineCourse(Long courseId) {
        //根据课程id查询课程
        Course course = selectById(courseId);
        //断言课程是否存在
        AssertUtil.isNotNull(course,"课程为空");
        boolean offLine = course.getStatus() == Course.STATE_OFFLINE;
        AssertUtil.isTrue(offLine,"课程状态不满足。");
        //上架 修改课程状态和上架时间
        course.setStatus(Course.STATE_ONLINE);
        course.setOnlineTime(new Date());
        updateById(course);
        //保存课程到es
        CourseType type = courseTypeService.selectById(course.getCourseTypeId());
        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);
        CourseDoc doc = new CourseDoc();
        //设置需要保存到Es的字段
        BeanUtils.copyProperties(course,doc);
        BeanUtils.copyProperties(courseMarket,doc);
        BeanUtils.copyProperties(courseSummary,doc);
        doc.setCourseTypeName(type.getName());//这里要单独赋值
        String chargeName = courseMarket.getCharge() == 1 ? "免费" : "收费";
        doc.setChargeName(chargeName);
        JSONResult result = courseSearchFeignClient.saveCourse(doc);
        AssertUtil.isTrue(result.isSuccess(),"课程上架失败");
        //课程发布成功
        //sendMessage(doc);
    }

    /**
     * 推消息
     * @param doc
     */
    private void sendMessage(CourseDoc doc) {
        /**
         * 生产者的消息体，到底该放什么
         *
         * 发送的消息内容是什么 content
         * 消息title
         * List<Long> userIds;
         *
         * MessageSmsDto {
         *     String content;
         *     String title;
         *     List<UserSmsDto> users;
         * }
         *
         * UserSmsDto{
         *         Long id;
         *         String phone;
         * }
         */
        MessageSmsDto messageSmsDto = new MessageSmsDto();
        messageSmsDto.setTitle("新课程发布"+doc.getName());
        messageSmsDto.setContent("亲，您关注的"+
                doc.getCourseTypeName()+
                "相关的课程"+doc.getName()+
                "已上线，尝鲜地址：<a href='localhost:6002/list.html?coursId="+doc.getId()+"'");
        List<UserSmsDto> userSmsDtos = Arrays.asList(
                new UserSmsDto(1L, "13330964748"),
                new UserSmsDto(2L, "18000534099")
        );
        messageSmsDto.setUsers(userSmsDtos);
        rocketMQTemplate.sendOneWay(
                COURSE_SMS_TOPIC+":"+COURSE_SMS_TAG,
                JSON.toJSONString(messageSmsDto)
        );

    }

    /**
     * 课程下架
     * @param courseId
     */
    @Override
    @Transactional
    public void offLineCourse(Long courseId) {
        //根据课程id查询课程
        Course course = selectById(courseId);
        //断言课程是否存在
        AssertUtil.isNotNull(course,"课程为空");
        boolean offLine = course.getStatus() == Course.STATE_ONLINE;
        AssertUtil.isTrue(offLine,"课程状态不满足。");
        //下架修改课程状态
        course.setStatus(Course.STATE_OFFLINE);
        updateById(course);
        //删除es中的课程
        JSONResult result = courseSearchFeignClient.deleteCourse(courseId);
        AssertUtil.isTrue(result.isSuccess(),"课程下架失败");
    }

    /**
     * 查询课程详情
     * @param courseId
     * @return
     */
    @Override
    public CourseDetailInfoVo searchCourseDetail(Long courseId) {
        AssertUtil.isNotNull(courseId,"请求不合理");
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"请求不合理");
        boolean onLine = course.getStatus() == Course.STATE_ONLINE;
        AssertUtil.isTrue(onLine,"课程没上线");

        //查询详情
        CourseDetail courseDetail = courseDetailService.selectById(courseId);
        //查询价格等信息
        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        //查询点击量
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);
        //查询老师
        Wrapper<CourseTeacher> ctwrapper = new EntityWrapper<>();
        ctwrapper.eq("course_id",courseId);
        List<CourseTeacher> courseteachers = courseTeacherService.selectList(ctwrapper);
        List<Long> teacherIds = courseteachers.stream().map(teacher -> teacher.getTeacherId()).collect(Collectors.toList());
        List<Teacher> teachers = teacherService.selectBatchIds(teacherIds);
        //查询章节
        Wrapper<CourseChapter> ccwrapper = new EntityWrapper<>();
        ccwrapper.eq("course_id",courseId);
        List<CourseChapter> chapters = courseChapterService.selectList(ccwrapper);
        //要为每一个章节查询对应的视屏
        //1.media微服务编写controller查询章节视屏
        //2.为media服务编写Feign接口+降级方案
        //3.course微服务依赖media的Feign接口，调用media查询章节视屏
        chapters.forEach(chapter->{
            JSONResult jsonResult = mediaFileFeignClient.searchMediaFiles(chapter.getId());//你可以搞成批量查询
            if(jsonResult.isSuccess() && jsonResult.getData() != null){
                List<MediaFile> fileList = JSONObject.parseArray(jsonResult.getData().toString(), MediaFile.class);
                chapter.getMediaFiles().addAll(fileList);
            }
        });
        CourseDetailInfoVo vo = new CourseDetailInfoVo();
        vo.setCourse(course);
        vo.setCourseChapters(chapters);
        vo.setCourseMarket(courseMarket);
        vo.setCourseSummary(courseSummary);
        vo.setCourseDetail(courseDetail);
        vo.setTeachers(teachers);
        return vo;
    }

    /**
     * 查询订单的必要信息
     * @param courseIds
     * @return
     */
    @Override
    public CourseOrderVo courseOrderInfo(String courseIds) {
        List<Long> ids = StrUtils.splitStr2LongArr(courseIds);
        Set<Long> setIds = ids.stream().collect(Collectors.toSet());
        //参数校验
        //业务判断
        boolean b = ids.size() == setIds.size();
        AssertUtil.isTrue(b,"非法请求");
        //根据课程id查询课程+销售表
        List<CourseItemVo> courseInfos = new ArrayList<>();
        BigDecimal totalAmount = new BigDecimal(0);
        for (Long id : setIds) {
            //3.封装课程和销售成 CourseItemVo
            Course course = selectById(id);
            AssertUtil.isNotNull(course,"非法请求");
            boolean onLine = course.getStatus() == Course.STATE_ONLINE;
            AssertUtil.isTrue(onLine,"非法请求");
            CourseMarket courseMarket = courseMarketService.selectById(id);
            AssertUtil.isNotNull(courseMarket,"非法请求");
            CourseItemVo courseItemInfoVo = new CourseItemVo(course,courseMarket);
            courseInfos.add(courseItemInfoVo);
            totalAmount = totalAmount.add(courseMarket.getPrice());
        }
        //4.将封装好的List<CourseItemVo> + 总金额，封装成CourserOrderVo
        return new CourseOrderVo(courseInfos,totalAmount);
    }
}
